﻿' LibWowArmory
' by Ronald M. Clifford (roncli@roncli.com)
'
' This source code is released under the GNU Library General Public License (LGPL) Version 2.1.

Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Xml.Serialization
Imports System.Web

Namespace roncliProductions.LibWowArmory

    Public Class CharacterAchievements
        Inherits WowArmoryData

#Region "Declarations"

        Private caPage As New CharacterAchievementsSchema.page
        Private strRealm As String
        Private strName As String
        Private aRecentAchievements As New List(Of Achievement)
        Private cCategories As New List(Of Category)

#End Region

        ''' <summary>
        ''' The realm the character is on
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Realm() As String
            Get
                Return strRealm
            End Get
            Set(ByVal value As String)
                strRealm = value
            End Set
        End Property

        ''' <summary>
        ''' The name of the character
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Name() As String
            Get
                Return strName
            End Get
            Set(ByVal value As String)
                strName = value
            End Set
        End Property

        ''' <summary>
        ''' The URL that will be used to retrieve the character's achievements from the Armory
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overrides ReadOnly Property URL() As String
            Get
                Return String.Format("http://www.wowarmory.com/character-achievements.xml?r={0}&n={1}", strRealm, strName)
            End Get
        End Property

        ''' <summary>
        ''' Indicates to the inherited class that this request does not require login
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overrides ReadOnly Property RequiresLogin() As Boolean
            Get
                Return False
            End Get
        End Property

        ''' <summary>
        ''' The total number of achievement points earned by this character
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property AchievementPointsEarned() As Integer
            Get
                Return caPage.achievements.First().summary.First().c.First().points
            End Get
        End Property

        ''' <summary>
        ''' The total possible number of achievement points available to earn in the game
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property AchievementPointsTotal() As Integer
            Get
                Return caPage.achievements.First().summary.First().c.First().totalPoints
            End Get
        End Property

        ''' <summary>
        ''' The total number of achievements earned by this character
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property AchievementsEarned() As Integer
            Get
                Return caPage.achievements.First().summary.First().c.First().earned
            End Get
        End Property

        ''' <summary>
        ''' The total possible number of achievements available to earn in the game
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property AchievementsTotal() As Integer
            Get
                Return caPage.achievements.First().summary.First().c.First().total
            End Get
        End Property

        ''' <summary>
        ''' The most recent achievements earned by this character
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property RecentAchievements() As List(Of Achievement)
            Get
                Return aRecentAchievements
            End Get
        End Property

        ''' <summary>
        ''' The achievement categories for this character
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Categories() As List(Of Category)
            Get
                Return cCategories
            End Get
        End Property

        ''' <summary>
        ''' A constructor to load a character's achievements by realm and character name
        ''' </summary>
        ''' <param name="strRealm"></param>
        ''' <param name="strName"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal strRealm As String, ByVal strName As String)
            Me.strRealm = strRealm
            Me.strName = strName
            Load()
        End Sub

        ''' <summary>
        ''' Loads the character's achievements from the armory
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Load()
            Dim strKey As String = String.Format("LibWowArmory.CharacterAchievements.{0}.{1}", strRealm, strName)
            If Cache.Cache(strKey) Is Nothing Then
                MyBase.Retrieve()

                Dim xsSerializer As New XmlSerializer(caPage.GetType())

                Dim srXML As New StringReader(MyBase.strData)

                caPage = CType(xsSerializer.Deserialize(srXML), CharacterAchievementsSchema.page)

                Cache.Cache.Insert(strKey, caPage, Nothing, Date.UtcNow.AddDays(1), Nothing, Caching.CacheItemPriority.Normal, Nothing)
            Else
                caPage = CType(Cache.Cache(strKey), CharacterAchievementsSchema.page)
            End If

            If caPage Is Nothing Then
                Throw New ArgumentException("The character you are trying to retrieve achievements for does not exist.")
            End If
            If caPage.characterInfo Is Nothing Then
                Throw New ArgumentException("The character you are trying to retrieve achievements for does not exist.")
            End If
            If caPage.characterInfo.First().character Is Nothing Then
                Throw New ArgumentException("The character you are trying to retrieve achievements for does not exist.")
            End If
            If caPage.achievements Is Nothing Then
                Throw New ArgumentException("The character you are trying to retrieve achievements for does not exist.")
            End If

            For Each aAchievement As CharacterAchievementsSchema.achievement In caPage.achievements.First().summary.First().achievement
                aRecentAchievements.Add(New Achievement(aAchievement.categoryId, aAchievement.dateCompleted, aAchievement.desc, aAchievement.icon, aAchievement.id, aAchievement.points, aAchievement.reward, aAchievement.title))
            Next

            For Each cCategory As CharacterAchievementsSchema.rootCategories_category In caPage.achievements.First().rootCategories.First().category
                cCategories.Add(New Category(cCategory.id, cCategory.name, (From c In cCategory.category Select New Subcategory(c.name)).ToList()))
            Next

            For Each cCategory As Category In cCategories
                Dim scCategory As CharacterAchievementsSchema.summary_category = caPage.achievements.First().summary.First().category(cCategories.IndexOf(cCategory))
                cCategory.Earned = scCategory.c.First().earned
                cCategory.EarnedPoints = scCategory.c.First().earnedPoints
                cCategory.Total = scCategory.c.First().total
                cCategory.TotalPoints = scCategory.c.First().totalPoints
            Next
        End Sub

        ''' <summary>
        ''' A character's achievements for a single category
        ''' </summary>
        ''' <param name="cCategory"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function CategoryAchievements(ByRef cCategory As Category) As CharacterAchievementsCategory
            Return New CharacterAchievementsCategory(strRealm, strName, cCategory.ID)
        End Function

        ''' <summary>
        ''' A class that encapsulates an achievement category
        ''' </summary>
        ''' <remarks></remarks>
        Public Class Category

            Private intEarned As Integer
            Private intEarnedPoints As Integer
            Private intID As Integer
            Private strName As String
            Private sSubcategories As List(Of Subcategory)
            Private intTotal As Integer
            Private intTotalPoints As Integer

            ''' <summary>
            ''' The number of achievements earned in this category
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Earned() As Integer
                Get
                    Return intEarned
                End Get
                Set(ByVal value As Integer)
                    intEarned = value
                End Set
            End Property

            ''' <summary>
            ''' The number of achievement points earned in this category
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property EarnedPoints() As Integer
                Get
                    Return intEarnedPoints
                End Get
                Set(ByVal value As Integer)
                    intEarnedPoints = value
                End Set
            End Property

            ''' <summary>
            ''' The identification number of the category
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property ID() As Integer
                Get
                    Return intID
                End Get
                Set(ByVal value As Integer)
                    intID = value
                End Set
            End Property

            ''' <summary>
            ''' The category's name
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Name() As String
                Get
                    Return strName
                End Get
                Set(ByVal value As String)
                    strName = value
                End Set
            End Property

            ''' <summary>
            ''' The subcategories contained in this category
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Subcategories() As List(Of Subcategory)
                Get
                    Return sSubcategories
                End Get
                Set(ByVal value As List(Of Subcategory))
                    sSubcategories = value
                End Set
            End Property

            ''' <summary>
            ''' The total number of achievements available to earn in this category
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Total() As Integer
                Get
                    Return intTotal
                End Get
                Set(ByVal value As Integer)
                    intTotal = value
                End Set
            End Property

            ''' <summary>
            ''' The total number of achievement points available to earn in this category
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property TotalPoints() As Integer
                Get
                    Return intTotalPoints
                End Get
                Set(ByVal value As Integer)
                    intTotalPoints = value
                End Set
            End Property

            ''' <summary>
            ''' A constructor that creates a new achievement category
            ''' </summary>
            ''' <param name="intID"></param>
            ''' <param name="strName"></param>
            ''' <remarks></remarks>
            Public Sub New(ByVal intID As Integer, ByVal strName As String, ByVal sSubcategories As List(Of Subcategory))
                Me.intID = intID
                Me.strName = strName
                Me.sSubcategories = sSubcategories
            End Sub

        End Class

        ''' <summary>
        ''' A class that encapsulates an achievement subcategory
        ''' </summary>
        ''' <remarks></remarks>
        Public Class Subcategory

            Private strName As String

            ''' <summary>
            ''' The subcategory's name
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Name() As String
                Get
                    Return strName
                End Get
                Set(ByVal value As String)
                    strName = value
                End Set
            End Property

            ''' <summary>
            ''' A constructor that creates a new achievement subcategory
            ''' </summary>
            ''' <param name="strName"></param>
            ''' <remarks></remarks>
            Public Sub New(ByVal strName As String)
                Me.strName = strName
            End Sub

        End Class

    End Class

End Namespace
